#include <iostream>

#include "CSignal.h"

using namespace std;

class CSIGRTMINHandler : public CSignalHandler {
private :
	sig_atomic_t _child1;
	sig_atomic_t _child2;
	sig_atomic_t _child3;

public :
	CSIGRTMINHandler() {
		_child1 = 0;
		_child2 = 0;
		_child3 = 0;
	};
	~CSIGRTMINHandler() {};

	virtual int handle(int signum, siginfo_t *si, void *sv) {
		// for RTS
		if(si->si_code==SI_QUEUE) {
			if(si->si_signo==SIGRTMIN) {
				_child1 = 1;

				cerr << "## 1st child ##" << endl;
				cerr << "child pid = " << si->si_pid << endl;
				cerr << "user data = " << si->si_value.sival_int << endl;
			}
			else if(si->si_signo==SIGRTMIN+1) {
				_child1 = 2;

				cerr << "## 2nd child ##" << endl;
				cerr << "child pid = " << si->si_pid << endl;
				cerr << "user data = " << si->si_value.sival_int << endl;
			}
			else if(si->si_signo==SIGRTMIN+2) {
				_child1 = 3;

				cerr << "## 3rd child ##" << endl;
				cerr << "child pid = " << si->si_pid << endl;
				cerr << "user data = " << si->si_value.sival_int << endl;

				// exit
				cerr << endl;
				cerr << "All of the child's signals are recieved, so exit" << endl;
				union sigval sv;
				sv.sival_int = 1; 
				CSignal::instance()->trigger(getpid(), SIGINT, sv);
			}
		}
		// for non-RTS
		else {
			cerr << "signal number = " << signum << endl;
		}
	};
};

int do_work(CSignalMask *sigmask)
{
	while(1) {
		if(sigmask!=NULL) {
			int signum = sigmask->waitinfo();

			if(signum==SIGRTMIN) {
				cerr << "1st child's signal from " << sigmask->get_wait_pid() << " with user data = " << sigmask->get_wait_value_int() << endl;
			}
			else if(signum==SIGRTMIN+1) {
				cerr << "2nd child's signal from " << sigmask->get_wait_pid() << " with user data = " << sigmask->get_wait_value_int() << endl;
			}
			else if(signum==SIGRTMIN+2) {
				cerr << "3rd child's signal from " << sigmask->get_wait_pid() << " with user data = " << sigmask->get_wait_value_int() << endl;
				break;
			}
			else {
				cerr << "huck~ what the heck is this signal : " << signum << endl;
				break;
			}
		}
		else sleep(3);
	}
}

int main(int argc, char **argv)
{
	if(argc<2) {
		cout << "Usages : " << argv[0] << " 1 or 2" << endl;
		cout << "\t1\tuse of user signal handlers" << endl;
		cout << "\t2\tuse of sigwait() with sigprocmask()" << endl;

		exit(-1);
	}

	// this signal handler will be inherent to the child processes
	CSIGRTMINHandler sigrt_handler;
	CSignal::instance()->register_handler(SIGRTMIN, &sigrt_handler);
	CSignal::instance()->register_handler(SIGRTMIN+1, &sigrt_handler);
	CSignal::instance()->register_handler(SIGRTMIN+2, &sigrt_handler);

	CSignalMask *sigmask = NULL;

	if(atoi(argv[1])==2) {
		sigmask = new CSignalMask();
		sigmask->add(SIGRTMIN);
		sigmask->add(SIGRTMIN+1);
		sigmask->add(SIGRTMIN+2);

		CSignal::instance()->block(sigmask);
	}

	pid_t parent = getpid();

	pid_t pid1 = fork();
	if(pid1==0) { // 1st child
		union sigval sv;

		sv.sival_int = 1; 
		CSignal::instance()->trigger(parent, SIGRTMIN, sv);

		exit(0);
	}
	else {
		pid_t pid2 = fork();
		if(pid2==0) { // 2nd child
			union sigval sv;

			sv.sival_int = 2;
			CSignal::instance()->trigger(parent, SIGRTMIN+1, sv);

			exit(0);
		}
		else {
			pid_t pid3 = fork();
			if(pid3==0) { // 3rd child
				union sigval sv;

				sv.sival_int = 3; 
				CSignal::instance()->trigger(parent, SIGRTMIN+2, sv);

				exit(0);
			}
			else { // parent
				do_work(sigmask);

				if(sigmask!=NULL) delete sigmask;

				cerr << "finally received the final signal(SIGRTMIN+2)" << endl;
				cerr << endl;
			}
		}
	}
}
